#ifndef __M_BENCH_H__
#define __M_BENCH_H__

// 引入日志系统头文件和时间处理头文件
#include "../logs/bitlog.h"
#include <chrono>

namespace bitlog {

/// @brief 基准测试函数，用于测量日志系统在多线程环境下的性能
/// @param loger_name 日志器的名称
/// @param thread_num 使用的线程数量
/// @param msglen 每条日志消息的长度
/// @param msg_count 总的日志消息数

void bench(const std::string &loger_name, size_t thread_num, size_t msglen, size_t msg_count)
{
    // 获取指定名称的日志器
    Logger::ptr lp = getLogger(loger_name);
    // 如果日志器不存在，直接返回
    if (lp.get() == nullptr) return;

    // 创建一个指定长度的字符串，内容为'1'
    std::string msg(msglen, '1');

    // 计算每个线程需要输出的日志数量
    size_t msg_count_per_thread = msg_count / thread_num;

    // 用于存储每个线程的耗时
    std::vector<double> cost_time(thread_num);

    // 用于存储所有线程对象
    std::vector<std::thread> threads;

    // 输出测试的基本信息
    std::cout << "输入线程数量: " << thread_num << std::endl;
    std::cout << "输出日志数量: " << msg_count << std::endl;
    std::cout << "输出日志大小: " << msglen * msg_count / 1024  << "KB" << std::endl;

    // 创建多个线程并启动日志记录任务
    for (int i = 0; i < thread_num; i++) {
        /*
        	•	threads.emplace_back([&, i](){ ... }); 这行代码的作用是：
	        •   在 threads 向量的末尾创建一个新的 std::thread 对象。
	        •	这个新线程对象使用了一个 Lambda 表达式作为线程的执行体，即 [](){ ... }。
	        •	这个 Lambda 表达式捕获了当前作用域中的变量 i，并在其内部定义了线程要执行的代码。
            std::vector<std::thread> threads;

            for (int i = 0; i < thread_num; i++) {
                threads.emplace_back([&, i](){
                    // 这里是线程要执行的任务代码
                });
            }
         * /
        threads.emplace_back([&, i](){
            /*
                std::chrono::high_resolution_clock::now()
                •	std::chrono::high_resolution_clock 是 C++ 标准库中提供的一个时钟类型，表示系统提供的高分辨率时钟。它通常具有非常高的精度，适合测量短时间间隔。
                •	now() 方法 返回一个表示当前时间点的 std::chrono::time_point 对象。
                auto start = std::chrono::high_resolution_clock::now();
                •	这行代码获取当前的高分辨率时间点，并将其存储在变量 start 中。
                •	auto 关键字让编译器自动推断 start 的类型，它实际上是 std::chrono::time_point<std::chrono::high_resolution_clock> 类型的对象。
                auto end = std::chrono::high_resolution_clock::now();
                •	同理，这行代码获取另一个当前的高分辨率时间点，并将其存储在变量 end 中。

                时间测量
                •	通过计算 end 和 start 之间的差值，可以得到代码块的执行时间。具体地，这通常用 std::chrono::duration 来表示时间间隔。
            */
           threads.emplace_back([&, i](){
            // 记录线程开始的时间点
            auto start = std::chrono::high_resolution_clock::now();
            
            // 每个线程执行消息数量为 msg_count_per_thread 的日志记录任务
            for(size_t j = 0; j < msg_count_per_thread; j++) {
                lp->fatal("%s", msg.c_str()); // 记录 FATAL 级别的日志
            }

            // 记录线程结束的时间点
            auto end = std::chrono::high_resolution_clock::now();

            // 计算线程的耗时
            auto cost = std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
            cost_time[i] = cost.count();

            // 计算线程的平均日志输出速率（条/秒）
            auto avg = msg_count_per_thread / cost_time[i];
            std::cout << "线程" << i << "耗时: " << cost.count() << "s" << " 平均：" << (size_t)avg << "/s\n";
        });
    }

    // 等待所有线程完成任务
    for(auto &thr : threads) {
        thr.join();
    }

    // 计算所有线程中耗时最长的那个线程的时间（即总消耗时间）
    double max_cost = 0;
    for (auto cost : cost_time) max_cost = max_cost < cost ? cost : max_cost;

    // 输出总的性能指标
    std::cout << "总消耗时间: " << max_cost << std::endl;
    std::cout << "平均每秒输出: " << (size_t)(msg_count / max_cost) << "条日志" << std::endl;
    std::cout << "平均每秒输出: " << (size_t)(msglen * msg_count / max_cost / 1024 / 1024) << "MB" << std::endl;
}

} // 命名空间 bitlog 结束

#endif // 头文件保护结束